dojo.provide('app.data.services');
dojo.require('dojo.io.script');
dojo.require('dojox.data.QueryReadStore');
(function() {

	dojo.declare('app.data.Store', dojox.data.QueryReadStore, {
		_filterResponse : function(results, deferred) {
			var ret = this.itemsProperty ? results[this.itemsProperty]:results;
			ret = ret.splice?ret:[ret];
			console.log(ret);
			return {identifier:'id',items:ret};
		},
		fetchItemByIdentity:function(keywordArgs){
			if(this._itemsByIdentity){
				var item = this._itemsByIdentity[keywordArgs.identity];
				if(!(item === undefined)){
					if(keywordArgs.onItem){
						var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
						keywordArgs.onItem.call(scope, {i:item, r:this});
					}
					return;
				}
			}
	
			// Otherwise we need to go remote
			// Set up error handler
			var _errorHandler = function(errorData, requestObject){
				var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
				if(keywordArgs.onError){
					keywordArgs.onError.call(scope, errorData);
				}
			};
			
			// Set up fetch handler
			var _fetchHandler = function(items, requestObject){
				var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
				try{
					console.log(items);
					// There is supposed to be only one result
					var item = null;
					if(items && items.length == 1){
						item = items[0];
					}
					
					// If no item was found, item is still null and we'll
					// fire the onItem event with the null here
					console.log(item);
					if(keywordArgs.onItem){
						keywordArgs.onItem.call(scope, item);
					}
				}catch(error){
					if(keywordArgs.onError){
						keywordArgs.onError.call(scope, error);
					}
				}
			};
			
			// Construct query
			var request = {serverQuery:{id:keywordArgs.identity}};
			request.url = this.url + '/' + keywordArgs.identity;
			// Dispatch query
			this._fetchItems(request, _fetchHandler, _errorHandler);
		},
		_fetchItems : function(request, fetchHandler, errorHandler) {
			var serverQuery = request.serverQuery || request.query || {};
			serverQuery.format = 'json';
			//Need to add start and count
			if(!this.doClientPaging){
				serverQuery.start = request.start || 0;
				// Count might not be sent if not given.
				if(request.count){
					serverQuery.count = request.count;
				}
			}
			if(!this.doClientSorting && request.sort){
				var sortInfo = [];
				dojo.forEach(request.sort, function(sort){
					if(sort && sort.attribute){
						sortInfo.push((sort.descending ? "-" : "") + sort.attribute);
					}
				});
				serverQuery.sort = sortInfo.join(',');
			}
			// Compare the last query and the current query by simply json-encoding them,
			// so we dont have to do any deep object compare ... is there some dojo.areObjectsEqual()???
			if(this.doClientPaging && this._lastServerQuery !== null &&
				dojo.toJson(serverQuery) == dojo.toJson(this._lastServerQuery)
				){
				this._numRows = (this._numRows === -1) ? this._items.length : this._numRows;
				fetchHandler(this._items, request, this._numRows);
			}else{
				var url = request.url || this.url;
				var xhrFunc = this.requestMethod.toLowerCase() == "post" ? dojo.xhrPost : dojo.xhrGet;
				var xhrHandler = xhrFunc({url:url, handleAs:"json-comment-optional", content:serverQuery, failOk: true});
				request.abort = function(){
					xhrHandler.cancel();
				};
				xhrHandler.addCallback(dojo.hitch(this, function(data){
					this._xhrFetchHandler(data, request, fetchHandler, errorHandler);
				}));
				xhrHandler.addErrback(function(error){
					errorHandler(error, request);
				});
				// Generate the hash using the time in milliseconds and a randon number.
				// Since Math.randon() returns something like: 0.23453463, we just remove the "0."
				// probably just for esthetic reasons :-).
				this.lastRequestHash = new Date().getTime()+"-"+String(Math.random()).substring(2);
				this._lastServerQuery = dojo.mixin({}, serverQuery);
			}
		}

	});

	function _getRequest(id, args) {
		if (dojo.isObject(id)) {
			id = dojo.objectToQuery(id);
			id = id ? "?" + id : "";
		}
		var _cnt = {};
		if (this.isJson) {
			_cnt.format = 'json';
		}
		if (args && (args.start >= 0 || args.count >= 0)) {
			_cnt.index = args.start || 0;
			_cnt.page = args.count == Infinity ? 10 : args.count;
		}

		var request = {
			url : this.servicePath + (id == null ? "" : id),
			content : _cnt,
			handleAs : this.isJson ? 'json' : 'text',
			contentType : this.isJson ? 'application/json' : 'text/plain',
			sync : dojox.rpc._sync,
			headers : {
				Accept : this.isJson ? 'application/json,application/javascript'
						: '*/*'
			}
		};
		dojox.rpc._sync = false;
		return request;
	}
	Services = new dojo.declare(null, {
		load : function(endpoints) {
			for (e in endpoints) {
				var endp = endpoints[e];
				var _ctor = app.data.Store, _schema = null;

				var props = {
					url : null,
					allowNoTrailingSlash : false,
					service : null
				};

				if (typeof endp === 'string') {
					props.url = endp;
				} else if (typeof endp === 'object') {
					props.url = (endp.schema && endp.schema.target)
							|| endp.target;
					_schema = endp.schema;
					_ctor = typeof endp.storeClass === 'function'
							&& endp.storeClass || _ctor;
					props.itemsProperty = endp.itemsProperty || e;
				}
				/*
				props._filterResponse = function(results, deferred) {
					var ret = this.itemsProperty ? {
						items : results[this.itemsProperty]
					} : results;
					if (typeof this.indexProp === 'string') {
						console.log('building reverse index');
						this._reverseIndex = [];
						for (idx in ret.items) {
							var item = ret.items[idx];
							var prop = item[this.indexProp];
							if (typeof prop != 'undefined') {
								this._reverseIndex[prop] = item;
							}
						}
						console.log(this._reverseIndex);
					}
					return ret;
				};

				
				 * props.fetch = function(request) { if(request.query){
				 * request.query.format = 'json'; } return
				 * this.inherited("fetch", arguments); }
				 

				props._fetchItems = function(request, fetchHandler,
						errorHandler) {
					var serverQuery = request.serverQuery || request.query;
					if (serverQuery) {
						serverQuery.format = 'json';
					}
					return this.inherited("_fetchItems", arguments);
				}

				/*
				 * props._processResults = function(results, deferred) { var res =
				 * this.itemsProperty && results[this.itemsProperty] || results;
				 * return { totalCount : res && res.length || 0, items : res } }
				 * 
				 * props._doQuery = function() { var _q =
				 * dojox.rpc.JsonRest.query; dojox.rpc.JsonRest.query =
				 * function(service, id, args) { return service(id, args); //
				 * GAMBI! } var ret = this.inherited('_doQuery', arguments);
				 * dojox.rpc.JsonRest.query = _q; return ret; }
				 * 
				 * props.service = new dojox.rpc.Rest(props.target, true,
				 * _schema, _getRequest);
				 */
				this[e] = {
					url : props.url,
					service : props.service,
					_store : new _ctor(props),
					store : function() {
						return this._store;
					}
				};

				var makeXhr = function(method, obj, getUrl) {
					obj[method] = function(data) {
						var prop = dojo.mixin({}, data);
						prop.url = typeof getUrl == 'function' ? getUrl.apply(
								this, [ data ]) : this.url;
						prop.handleAs = 'json';
						if (prop.content) {
							prop.content.format = 'json';
						} else if (prop.postData) {
							prop.postData = (prop.postData.length > 0 ? ''
									: '&')
									+ 'format=json';
						} else {
							prop.url = (this.url.indexOf('?') > 0 ? '' : '?')
									+ 'format=json';
						}
						return dojo.xhr(method.toUpperCase(), prop);
					};
				};

				makeXhr('Get', this[e]);
				makeXhr('Post', this[e]);
				makeXhr('Delete', this[e], function(data) {
					return this.url + '/' + data.id;
				});
				makeXhr('Put', this[e]);

			}
		}
	})();
})();